package com.yuzhi.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuzhi.common.contant.CacheNames;
import com.yuzhi.common.contant.Constants;
import com.yuzhi.common.contant.UserConstants;
import com.yuzhi.common.core.domain.BaseEntity;
import com.yuzhi.common.core.domain.entity.SysDept;
import com.yuzhi.common.core.domain.entity.SysRole;
import com.yuzhi.common.core.domain.entity.SysUser;
import com.yuzhi.common.core.page.PageDataInfo;
import com.yuzhi.common.core.service.UserService;
import com.yuzhi.common.enums.DataScopeTypeEnum;
import com.yuzhi.common.exception.ServiceException;
import com.yuzhi.common.helper.DataBaseHelper;
import com.yuzhi.common.helper.LoginHelper;
import com.yuzhi.common.util.StreamUtils;
import com.yuzhi.common.util.StringUtils;
import com.yuzhi.common.util.spring.SpringUtils;
import com.yuzhi.system.domain.SysUserDept;
import com.yuzhi.system.domain.SysUserDeptScope;
import com.yuzhi.system.domain.SysUserRole;
import com.yuzhi.system.domain.bo.SysUserDeptScopeBo;
import com.yuzhi.system.domain.request.SysUserReq;
import com.yuzhi.system.domain.vo.SysOssVo;
import com.yuzhi.system.mapper.*;
import com.yuzhi.system.service.ISysDeptService;
import com.yuzhi.system.service.ISysUserDeptScopeService;
import com.yuzhi.system.service.ISysUserService;
import io.vavr.control.Option;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户 业务层处理
 *
 * @author auto
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysUserServiceImpl implements ISysUserService, UserService {

    private final SysUserMapper baseMapper;
    private final SysDeptMapper deptMapper;
    private final SysRoleMapper roleMapper;
    private final SysUserRoleMapper userRoleMapper;
    private final SysUserDeptMapper userDeptMapper;
    private final ISysDeptService sysDeptService;
    private final ISysUserDeptScopeService sysUserDeptScopeService;

    @Override
    public PageDataInfo<SysUser> selectPageUserList(SysUserReq user) {
        Page<SysUser> page = baseMapper.selectPageUserList(user.getPageQuery().build(), this.buildQueryWrapper(user));
        return PageDataInfo.build(page);
    }

    /**
     * 根据条件分页查询用户列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public List<SysUser> selectUserList(SysUserReq user) {
        return baseMapper.selectUserList(this.buildQueryWrapper(user));
    }

    private Wrapper<SysUser> buildQueryWrapper(SysUserReq user) {
        Map<String, Object> params = user.getParams();
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper.eq("u.deleted", Constants.UNDELETED)
            .eq(ObjectUtil.isNotNull(user.getId()), "u.id", user.getId())
            .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
            .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
            .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                "u.create_time", params.get("beginTime"), params.get("endTime"))
            .and(StringUtils.isNotBlank(user.getDeptId()), w -> {
                List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
                    .select(SysDept::getId)
                    .apply(DataBaseHelper.findInSet(user.getDeptId(), "ancestors")));
                List<String> ids = StreamUtils.toList(deptList, SysDept::getId);
                ids.add(user.getDeptId());
                w.in("sud.dept_id", ids);
            });
        return wrapper;
    }

    /**
     * 根据条件分页查询已分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public PageDataInfo<SysUser> selectAllocatedList(SysUserReq user) {
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper.eq("u.deleted", UserConstants.USER_NORMAL)
            .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId())
            .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
            .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
            .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber());
        Page<SysUser> page = baseMapper.selectAllocatedList(user.getPageQuery().build(), wrapper);
        return PageDataInfo.build(page);
    }

    /**
     * 根据条件分页查询未分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public PageDataInfo<SysUser> selectUnallocatedList(SysUserReq user) {
        List<String> userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId());
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper.eq("u.deleted", UserConstants.USER_NORMAL)
            .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id"))
            .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds)
            .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
            .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber());
        Page<SysUser> page = baseMapper.selectUnallocatedList(user.getPageQuery().build(), wrapper);
        return PageDataInfo.build(page);
    }

    /**
     * 通过用户名查询用户
     *
     * @param userName 用户名
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserByUserName(String userName) {
        return baseMapper.selectUserByUserName(userName);
    }

    /**
     * 通过手机号查询用户
     *
     * @param phonenumber 手机号
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserByPhonenumber(String phonenumber) {
        return baseMapper.selectUserByPhonenumber(phonenumber);
    }

    /**
     * 通过用户ID查询用户
     *
     * @param userId 用户ID
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserById(String userId) {
        return baseMapper.selectUserById(userId);
    }

    /**
     * 查询用户所属角色组
     *
     * @param userName 用户名
     * @return 结果
     */
    @Override
    public String selectUserRoleGroup(String userName) {
        List<SysRole> list = roleMapper.selectRolesByUserName(userName);
        if (CollUtil.isEmpty(list)) {
            return StringUtils.EMPTY;
        }
        return StreamUtils.join(list, SysRole::getRoleName);
    }

    /**
     * 校验用户名称是否唯一
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public boolean checkUserNameUnique(SysUser user) {
        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
            .eq(SysUser::getUserName, user.getUserName())
            .ne(ObjectUtil.isNotNull(user.getId()), SysUser::getId, user.getId()));
        return !exist;
    }

    /**
     * 校验手机号码是否唯一
     *
     * @param user 用户信息
     */
    @Override
    public boolean checkPhoneUnique(SysUser user) {
        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
            .eq(SysUser::getPhonenumber, user.getPhonenumber())
            .ne(ObjectUtil.isNotNull(user.getId()), SysUser::getId, user.getId()));
        return !exist;
    }

    /**
     * 校验email是否唯一
     *
     * @param user 用户信息
     */
    @Override
    public boolean checkEmailUnique(SysUser user) {
        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
            .eq(SysUser::getEmail, user.getEmail())
            .ne(ObjectUtil.isNotNull(user.getId()), SysUser::getId, user.getId()));
        return !exist;
    }

    /**
     * 校验用户是否允许操作
     *
     * @param user 用户信息
     */
    @Override
    public void checkUserAllowed(SysUser user) {
        if (ObjectUtil.isNotNull(user.getId()) && user.isAdmin()) {
            throw new ServiceException("不允许操作超级管理员用户");
        }
    }

    /**
     * 校验用户是否有数据权限
     *
     * @param userId 用户id
     */
    @Override
    public void checkUserDataScope(String userId) {
        if (!LoginHelper.isAdmin()) {
            SysUserReq user = new SysUserReq();
            user.setId(userId);
            List<SysUser> users = this.selectUserList(user);
            if (CollUtil.isEmpty(users)) {
                throw new ServiceException("没有权限访问用户数据！");
            }
        }
    }

    /**
     * 新增保存用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertUser(SysUser user) {
        // 新增用户信息
        int rows = baseMapper.insert(user);
        // 新增用户与角色管理
        insertUserRole(user);
        // 新增用户与部门管理
        insertUserDept(user);
        return rows;
    }

    /**
     * 注册用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public boolean registerUser(SysUser user) {
        user.setCreatorName(user.getUserName());
        user.setUpdaterName(user.getUserName());
        return baseMapper.insert(user) > 0;
    }

    /**
     * 修改保存用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateUser(SysUser user) {
        String userId = user.getId();
        // 删除用户与角色关联
        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
        userDeptMapper.delete(new LambdaQueryWrapper<SysUserDept>().eq(SysUserDept::getUserId, userId));
        // 新增用户与角色管理
        insertUserRole(user);
        // 新增用户与部门管理
        insertUserDept(user);
        return baseMapper.updateById(user);
    }

    /**
     * 用户授权角色
     *
     * @param userId  用户ID
     * @param roleIds 角色组
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertUserAuth(String userId, String[] roleIds) {
        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
            .eq(SysUserRole::getUserId, userId));
        insertUserRole(userId, roleIds);
    }

    /**
     * 修改用户状态
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int updateUserStatus(SysUser user) {
        return baseMapper.updateById(user);
    }

    /**
     * 修改用户基本信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int updateUserProfile(SysUser user) {
        return baseMapper.updateById(user);
    }

    /**
     * 修改用户头像
     *
     * @param userName 用户名
     * @param avatar   头像地址
     * @return 结果
     */
    @Override
    public boolean updateUserAvatar(String userName, String avatar) {
        return baseMapper.update(null,
            new LambdaUpdateWrapper<SysUser>()
                .set(SysUser::getAvatar, avatar)
                .eq(SysUser::getUserName, userName)) > 0;
    }

    /**
     * 重置用户密码
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int resetPwd(SysUser user) {
        return baseMapper.updateById(user);
    }

    /**
     * 重置用户密码
     *
     * @param userName 用户名
     * @param password 密码
     * @return 结果
     */
    @Override
    public int resetUserPwd(String userName, String password) {
        return baseMapper.update(null,
            new LambdaUpdateWrapper<SysUser>()
                .set(SysUser::getPassword, password)
                .eq(SysUser::getUserName, userName));
    }

    /**
     * 新增用户角色信息
     *
     * @param user 用户对象
     */
    public void insertUserRole(SysUser user) {
        this.insertUserRole(user.getId(), user.getRoleIds());
    }

    /**
     * 新增用户角色信息
     *
     * @param user 用户对象
     */
    public void insertUserDept(SysUser user) {
        this.insertUserDept(user.getId(), user.getDeptIds());
    }

    /**
     * 新增用户角色信息
     *
     * @param userId  用户ID
     * @param roleIds 角色组
     */
    public void insertUserRole(String userId, String[] roleIds) {
        if (ArrayUtil.isNotEmpty(roleIds)) {
            // 新增用户与角色管理
            List<SysUserRole> list = StreamUtils.toList(Arrays.asList(roleIds), roleId -> {
                SysUserRole ur = new SysUserRole();
                ur.setUserId(userId);
                ur.setRoleId(roleId);
                return ur;
            });
            userRoleMapper.insertBatch(list);
        }
    }

    /**
     * 新增用户部门信息
     *
     * @param userId  用户ID
     * @param deptIds 部门组
     */
    public void insertUserDept(String userId, String[] deptIds) {
        if (ArrayUtil.isNotEmpty(deptIds)) {
            // 新增用户与角色管理
            List<SysUserDept> list = StreamUtils.toList(Arrays.asList(deptIds), deptId -> {
                SysUserDept ud = new SysUserDept();
                ud.setUserId(userId);
                ud.setDeptId(deptId);
                return ud;
            });
            userDeptMapper.insertBatch(list);
        }
    }

    /**
     * 通过用户ID删除用户
     *
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserById(String userId) {
        // 删除用户与角色关联
        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
        return baseMapper.deleteById(userId);
    }

    /**
     * 批量删除用户信息
     *
     * @param userIds 需要删除的用户ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserByIds(String[] userIds) {
        for (String userId : userIds) {
            checkUserAllowed(new SysUser(userId));
            checkUserDataScope(userId);
        }
        List<String> ids = Arrays.asList(userIds);
        // 删除用户与角色关联
        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, ids));
        // 删除用户与部门关联
        userDeptMapper.delete(new LambdaQueryWrapper<SysUserDept>().in(SysUserDept::getUserId, ids));
        return baseMapper.deleteBatchIds(ids);
    }

    @Override
    public String selectNickNameById(String userId) {
        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
            .select(SysUser::getNickName).eq(SysUser::getId, userId));
        return ObjectUtil.isNull(sysUser) ? null : sysUser.getNickName();
    }

    @Override
    public String selectUserNameById(String userId) {
        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getUserName).eq(SysUser::getId, userId));
        return ObjectUtil.isNull(sysUser) ? null : sysUser.getUserName();
    }

    @Override
    public void refreshUserDataScope(List<String>  userIds) {
        //查询所有部门信息
        List<SysDept> depts = this.deptMapper.selectAllDeptIds();

        for (String userId : userIds){
            try {
                sysUserDeptScopeService.deleteByUserId(userId);
                SysUser sysUser = this.selectUserById(userId);
                if (ObjectUtil.isNotNull(sysUser)){
                    List<SysRole> sysRoles = this.roleMapper.selectRolePermissionByUserId(userId);
                    if (CollUtil.isNotEmpty(sysRoles)){
                        //过滤角色的权限等级（1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限）
                        //如果包含1，则给用户分配所有的部门id，如果不包含1，则根据其他的权限范围进行拼合
                        Set<String> deptIds = dealUserDeptScope(userId,depts,sysRoles);
                        deptIds.forEach(deptId -> {
                            SysUserDeptScopeBo sysUserDeptScopeBo = new SysUserDeptScopeBo().setUserId(userId).setDeptId(deptId);
                            sysUserDeptScopeService.insertByBo(sysUserDeptScopeBo);
                        });
                    }
                }
            }catch (Exception e){
                log.error("刷新用户数据权限范围异常，用户id为:"+userId+":{}", e.getMessage());
            }
        }
    }

    @Override
    public Map<String, String> selectUserName(List<String> regionUser) {
        if (CollectionUtils.isEmpty(regionUser)) {
            return Collections.emptyMap();
        }
        List<SysUser> listUser = baseMapper.selectUserName(regionUser);
        return listUser.stream()
                .collect(Collectors.toMap(
                        SysUser::getId,
                        SysUser::getNickName,
                        (oldVal, newVal) -> oldVal
                ));
    }

    @Override
    public String getUserIdsByNames(String userNames) {
        return baseMapper.selectUserIdsByNames(userNames);
    }


    private Set<String> dealUserDeptScope(String userId, List<SysDept> depts, List<SysRole> sysRoles){
        List<String> dataScopes = sysRoles.stream().map(SysRole::getDataScope).distinct().collect(Collectors.toList());

        Set<String> deptIds = new HashSet<>(5);
        if (dataScopes.contains(DataScopeTypeEnum.ALL.getCode())){
            deptIds.addAll(depts.stream().map(BaseEntity::getId).collect(Collectors.toSet()));
            return deptIds;
        }

        if (dataScopes.contains(DataScopeTypeEnum.CUSTOM.getCode())){
            Set<String> roleIds = sysRoles.stream().filter(role -> role.getDataScope().equals(DataScopeTypeEnum.CUSTOM.getCode()))
                    .map(BaseEntity::getId)
                    .collect(Collectors.toSet());
            roleIds.stream().forEach(roleId -> {
                List<String> deptIdsByRoleId = this.deptMapper.selectDeptListByRoleId(roleId, 0);
                Option.when(CollUtil.isNotEmpty(deptIdsByRoleId),() -> deptIds.addAll(deptIdsByRoleId));
            });
        }

        if (dataScopes.contains(DataScopeTypeEnum.DEPT.getCode())){
            List<String> deptIdsByUserId = userDeptMapper.selectdeptIdsByUserId(userId);
            Option.when(CollUtil.isNotEmpty(deptIdsByUserId),() -> deptIds.addAll(deptIdsByUserId));
        }

        if (dataScopes.contains(DataScopeTypeEnum.DEPT_AND_CHILD.getCode())){
            List<String> deptIdsByUserId = userDeptMapper.selectdeptIdsByUserId(userId);
            deptIdsByUserId.stream().forEach(deptId -> {
                deptIds.add(deptId);
                List<SysDept> sysDepts = sysDeptService.selectChildrenDeptById(deptId);
                Option.when(CollUtil.isNotEmpty(sysDepts),() -> deptIds.addAll(sysDepts.stream().map(BaseEntity::getId).collect(Collectors.toSet())));
            });

            Option.when(CollUtil.isNotEmpty(deptIdsByUserId),() -> deptIds.addAll(deptIdsByUserId));
        }

        return deptIds;
    }

    /**
     * 根据用户ID集合查询用户信息
     * @param userIds 用户ID
     * @return
     */
    @Override
    public List<SysUser> selectUserByIds(List<String> userIds)
    {
        LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(SysUser::getStatus,"0");  //帐号状态（0正常 1停用）
        lqw.eq(SysUser::getDeleted,0); //未删除
        lqw.in(SysUser::getId, userIds);

        List<SysUser>  sysUserList  = baseMapper.selectList(lqw);
        return  sysUserList;
    }

}
